<template>
  <div>
    <el-row
      style="height: 40px;margin-left: 10px;margin-top:10px;"
      type="flex"
      align="middle"
    />
    <div class="title">
      <span>{{ baseFrom.name }}</span>
    </div>
    <el-form v-if="showAdd" class="form-approval" label-width="140px">
      <el-form-item label="审批名称">
        <el-input v-model="baseFrom.name" style="width: 50%" size="mini" placeholder="请输入审批标题" />
      </el-form-item>
      <el-form-item label="所属分类">
        <el-select v-model="baseFrom.groupType" size="mini" placeholder="请选择">
          <el-option label="出勤休假" :value="1" />
          <el-option label="财务" :value="2" />
          <el-option label="人事" :value="3" />
          <el-option label="行政" :value="4" />
          <el-option label="其他" :value="5" />
        </el-select>
      </el-form-item>
      <el-form-item label="业务线">
        <el-select v-model="baseFrom.tenantId" size="mini" placeholder="业务系统">
          <!-- 业务线 -->
          <el-option
            v-for="item in businessLines"
            :key="item.key"
            :label="item.value"
            :value="item.key"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="审批说明：">
        <el-input v-model="baseFrom.description" size="mini" placeholder="最多100字" />
      </el-form-item>
      <el-form-item label="审批意见填写提示：">
        <el-input v-model="baseFrom.opinionPrompt" size="mini" placeholder="请输入审批意见填写提示" />
      </el-form-item>
      <el-form-item label="审批意见是否必填">
        <el-checkbox v-model="baseFrom.opinionRequired" :true-label="1" :false-label="0">必填</el-checkbox>
      </el-form-item>
      <el-form-item>
        <el-button type="warning" size="small" icon="el-icon-back" @click="goBack">返回 </el-button>
        <el-button type="primary" size="small" @click="toDesign">去配置 <i class="el-icon-right" /></el-button>
      </el-form-item>
    </el-form>
    <div
      v-show="!showAdd"
      v-loading="loading"
      class="wrap"
      :element-loading-text="loadingText"
      element-loading-background="rgba(0, 0, 0, 0)"
    >

      <div class="content">
        <!--左侧工具栏-->
        <div id="stencil" class="sider" />
        <div class="panel">
          <div class="toolbar">
            <tool-bar :flow-graph="flowGraph" :save-func="saveJSON" :to-basic="toBasic" />
          </div>
          <!--绘图面板组件-->
          <div id="container" class="x6-graph" />
        </div>
        <div class="config">
          <!--配置面板组件：传递flowGraph给子组件使用-->
          <select-panel :current-node="currentNode" />
        </div>
      </div>
    </div>
  </div>

</template>
<script>

import toolBar from '@/components/ToolBar'
import SelectPanel from '@/components/SelectPanel'
import FlowGraph from './graph'
import { getBpmJSON, publishBpmJSON } from '@/api/approval'
import { getUsername } from '@/utils/authorized'
import NodeType from '@/constant/nodeType'
import { getBusinessLinesOption } from '@/api/approval'
export default {
  components: {
    toolBar, SelectPanel
  },
  data() {
    return {
      processDefinitionKey: this.$route.params.key, // 定义传过来的key
      operateType: this.$route.query.type, // 操作类型
      loading: false, // 进度条
      flowGraph: null,
      currentNode: null, // 当前节点
      bpmJSON: null, // json
      flowData: null,
      godArr: [], // 上帝视角的数据
      loadingText: '',
      showAdd: false, // 显示新增弹层
      baseFrom: {
        name: null,
        tenantId: null,
        description: '',
        groupType: 5,
        icon: '',
        opinionPrompt: '',
        opinionRequired: 0
      },
      businessLines: [] // 业务线数据
    }
  },
  created() {
    if (this.operateType === 'add') {
      this.showAdd = true
    } else {
      this.getBpmJSON()
    }
    this.getBusinessLinesOption() // 获取业务线数据
  },
  mounted() {
    this.initFlowGraph()
  },
  methods: {
    toBasic() {
      this.showAdd = true
    },
    toDesign() {
      if (this.baseFrom.name && this.baseFrom.tenantId && this.baseFrom.groupType) {
      // if (this.baseFrom.name) {
        this.showAdd = false
      } else {
        this.$message.warning('请填写审批名称,选择业务线, 选择审批类型')
      }
    },
    // 获取业务线数据
    async getBusinessLinesOption() {
      this.businessLines = await getBusinessLinesOption()
    },
    // 初始化
    initFlowGraph() {
      this.flowGraph = new FlowGraph()
      // 节点点击事件
      this.registerEvent()
    },
    // 注册事件
    registerEvent() {
      this.registerNodeClick() // 注册节点点击事件
      this.registerPanelClick() // 注册空白区域点击事件
    },
    registerNodeClick() {
      this.flowGraph.graph.on('node:click', ({ e, x, y, node, view }) => {
      //  打印节点
        this.currentNode = node
      })
    },
    // 注册面板事件
    registerPanelClick() {
      this.flowGraph.graph.on('blank:click', ({ e, x, y, node, view }) => {
      //  重置节点
        this.currentNode = null
      })
    },
    // 获取json
    async getBpmJSON() {
      this.loadingText = '流程加载中...'
      try {
        if (this.processDefinitionKey) {
          this.loading = true
          const flowData = await getBpmJSON(this.processDefinitionKey)
          this.flowData = flowData || {}
          this.baseFrom = flowData || {}
          const { flowDataJson } = this.flowData
          if (flowDataJson && flowDataJson !== '原始json') {
            this.bpmJSON = JSON.parse(flowDataJson) // 设置json
            this.flowGraph.graph.fromJSON(this.bpmJSON)
          }
        } else {
          this.$message.warning('bpm的定义key不存在')
        }
      } catch (error) {
        console.log(error)
      } finally {
        setTimeout(() => (this.loading = false), 1000)
      }
    },
    // 保存json
    saveJSON() {
      const json = this.flowGraph.graph.toJSON()
      // this.createFlowJSON(json)
      if (this.checkAloneNode(json.cells)) {
        this.$message.warning('存在未连线的Node节点')
        return
      }
      if (json && json.cells && json.cells.length) {
        this.$confirm('新的流程发布将会重新发布流程的新版本,确定发布吗').then(async() => {
          try {
            this.loadingText = '流程发布中...'
            this.loading = true
            await publishBpmJSON(this.createFlowJSON(json))
            this.$message.success('发布新流程成功！')
            this.loading = false
            this.$router.push('/approval')
          } catch (error) {
            console.log(error)
            this.loading = false
            this.$message.error('发布新流程失败, 错误信息:' + error)
          }
        })
      } else {
        this.$message.warning('不能发布空的流程')
      }
    },
    // 检查单独节点
    checkAloneNode(cells) {
      const allEdges = cells.filter((item) => item.shape === 'edge') // 所有的边
      const allNode = cells.filter((item) => item.shape !== 'edge') // 找到非节点
      let isLine = false
      allNode.forEach(node => {
        // 检查是否有节点
        if (!allEdges.some(edge => edge.target.cell === node.id) && !allEdges.some(edge => edge.source.cell === node.id)) {
          isLine = true // 表示有节点并没有连上线
        }
      })
      return allNode.length > 1 && isLine
    },
    // 生成流程数据的json
    createFlowJSON(flowDataJson) {
      const baseData = {
        createdBy: this.operateType === 'add' ? getUsername() : null,
        modifiedBy: this.operateType !== 'add' ? getUsername() : null,
        ...this.baseFrom
      }
      // 循环每个节点
      const flowData = this.transNode(flowDataJson.cells)
      this.godArr = [] // 重新设置上帝视角数据为空
      const userRange = null
      // const userRange = typeof this.flowData.userRange === 'string' ? JSON.parse(this.flowData.userRange) : this.flowData.userRange
      return {
        baseData,
        userRange,
        flowData,
        flowDataJson: JSON.stringify(flowDataJson)
      }
    },
    // 转化节点
    transNode(cells) {
      const cell = this.findTopNode(cells) // 找到top节点
      const allEdges = cells.filter((item) => item.shape === 'edge') // 所有的边
      let node = {}
      const { title: name, options } = cell.data
      let userRange = {} //
      if (options.userType === 6) {
        // 如果是审批成员
        userRange = [{
          objectName: options.options.name,
          objectId: options.options.id,
          objectType: 3
        }]
      }
      if (options.userType === 1) {
        // 如果是指定成员
        userRange = options.options.map(item => ({
          objectName: item.userName,
          objectId: item.email,
          objectType: 2
        }))
      }
      if (options.userType === 4) {
        // 如果是发起人自己
        userRange = [{
          objectType: 4
        }]
      }

      // 找到了子节点
      node = {
        id: cell.id, // 节点标识
        type: cell.data.NodeType, // 节点类型
        name: name, // 节点名称
        userRange, // 指定的审批成员
        multiApproveMode: options ? options.multiApproveMode : '',
        mangerLevel: options ? options.mangerLevel : '',
        userType: options ? options.userType : ''
      }
      const startNode = { 'name': '开始', 'type': 'start' }
      const endNode = { 'name': '结束', 'type': 'end' }
      return [startNode, node, ...this.createNodeJSON(cells, allEdges, cell.id), endNode]
    },
    // 找到顶级节点的id => 顶级节点是有尾没头的
    findTopNode(cells) {
      const allEdges = cells.filter((item) => item.shape === 'edge') // 所有的边
      if (cells.length === 1) return cells[0]
      let node = null
      cells.forEach((item) => {
      // 能够找到以该节点做为源头的
        if (
          allEdges.find((obj) => obj.source.cell === item.id) &&
        !allEdges.find((obj) => obj.target.cell === item.id)
        ) {
        //  找不到以该节点为结尾的
        //  说明找到了起始节点
          node = { ...item }
        }
      })
      return node
    },
    // 生成节点的json
    createNodeJSON(cells, allEdges, parentNodeId) {
      const arr = []

      // 找到所有的子节点Id
      // 因为有可能多个的父节点是一个人
      const childIdList = allEdges
        .filter((obj) => obj.source.cell === parentNodeId)
        .map((item) => item.target.cell)
      if (!childIdList.length) return arr
      cells.forEach((cell) => {
      // 寻找子节点的集合
        if (childIdList.some((item) => item === cell.id)) {
          let node = {}
          const { title: name, options } = cell.data
          if (
            cell.data.NodeType === NodeType.APPRPVAL_MAN ||
          cell.data.NodeType === NodeType.SEND_MAN
          ) {
            let userRange = []
            if (options && options.options) {
              if (options && options.options) {
                if (options.userType === 6) {
                  // 如果是审批成员
                  userRange = [{
                    objectName: options.options.name,
                    objectId: options.options.id,
                    objectType: 3
                  }]
                }
                if (options.userType === 1) {
                  // 如果是指定成员
                  userRange = options.options.map(item => ({
                    objectName: item.userName,
                    objectId: item.email,
                    objectType: 2
                  }))
                }
                if (options.userType === 4) {
                  // 如果是发起人自己
                  userRange = [{
                    objectType: 4
                  }]
                }
              }
            }
            // 找到了子节点
            node = {
              id: cell.id, // 节点标识
              type: cell.data.NodeType, // 节点类型
              name: name, // 节点名称
              userRange: userRange, // 指定的审批成员
              multiApproveMode: options ? options.multiApproveMode : '',
              mangerLevel: options ? options.mangerLevel : '',
              userType: options ? options.userType : ''
            }
            arr.push(node)
          }
          if (cell.data.NodeType === NodeType.CONDITION) {
            const conditionNode = { node: [], pid: parentNodeId, type: 'condition' } // 条件节点数据
            // 如果是条件节点 需要做递归嵌套
            const nodeArr = []
            let conditionExpression = ''
            if (options && options.length) {
            // 循环生成条件
              conditionExpression = options
                .map((item) => {
                  return `${item.options.leftVaribale} ${item.options.operate} ${item.options.valueVariable} ${item.options.lastJoin}`
                })
                .join(' ')
            }
            nodeArr.push({
              conditionExpression: '${' + conditionExpression + '}',
              name: '条件',
              type: 'cond',
              priority: 1
            })
            const sameArr = this.sameNodeArr(parentNodeId)
            if (sameArr) {
              sameArr.push(nodeArr)
            } else {
              conditionNode.node.push(nodeArr) // 添加到子选项中
              arr.push(conditionNode) // 添加到当前数组中
              this.godArr.push(conditionNode)
            }
            const childArr = this.createNodeJSON(cells, allEdges, cell.id)
            if (childArr.length) {
              nodeArr.push(...childArr)
            }
          } else {
            const childArr = this.createNodeJSON(cells, allEdges, cell.id)
            if (childArr.length) {
              arr.push(...childArr) // 添加到子节点
            }
          }
        }
      })
      return arr
    },
    // 同级的节点数组
    sameNodeArr(id) {
      const obj = this.godArr.find(item => item.pid === id)
      return obj ? obj.node : null
    },
    goBack() {
      this.$router.go(-1)
    }
  }
}
</script>

<style lang="scss" scoped>
.wrap {
  width: 100%;
  height: 100%;
  .header {
    display: flex;
    justify-content: space-between;
    height: 48px;
    line-height: 48px;
    padding-left: 16px;
    padding-right: 32px;
    background: #fff;
    box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.1);
    position: relative;
    color: rgba(0, 0, 0, 0.45);
  }
  .content {
    display: flex;
    height: calc(100% - 48px);
    .sider {
      position: relative;
      width: 250px;
      height: 800px;
      border-right: 1px solid rgba(0, 0, 0, 0.08);
    }
    .panel {
      height: 100%;
      width: 65%;
      .toolbar {
        display: flex;
        align-items: center;
        height: 38px;
        background-color: #f7f9fb;
        border-bottom: 1px solid rgba(0, 0, 0, 0.08);
      }
    }
    .config {
      box-sizing: border-box;
      flex: 1 ;
      height: 100%;
      border-left: 1px solid rgba(0, 0, 0, 0.08);
    }
  }
}
      .form-approval{
        width: 800px;
        margin: 30px auto;
        margin-top: 90px;
        line-height: 2;
        .formItem{
          display: flex;
          margin: 30px 0;
          .tit{
            display: inline-block;
            text-align: right;
            width: 300px;
            color: #666666;
          }
          .contInput{
            flex: 1;
          }
        }
      }
      .title {
        position: absolute;
        left: 0;
        top: 10px;
        text-align: center;
        width: 100%;
        span {
          font-size: 18px;
          font-weight: bold;
          user-select: none;
          line-height: 38px;
        }
      }
</style>
